'Copyright (C) 2009 Christiaan Cable
'
'This program is free software; you can redistribute it and/or
'modify it under the terms of the GNU General Public License
'as published by the Free Software Foundation; either version 3
'of the License, or (at your option) any later version.
'
'This program is distributed in the hope that it will be useful,
'but WITHOUT ANY WARRANTY; without even the implied warranty of
'MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
'GNU General Public License for more details (LICENCE.TXT).

Imports System.Threading
Imports UA
Imports System.IO
Imports System.Security.AccessControl
Imports System.Security.Principal

Module Module1

    Declare Auto Function DestroyIcon Lib "User32.dll" (ByVal hIcon As IntPtr) As Int32
    Private icoUA As New Icon(GetType(Module1).Assembly.GetManifestResourceStream("UATrayIcon.ua16x16.ico"))
    Private AppDataPath As String = GetAppDataPath()

    'isp data
    Public ISPReturnData As ISPReturnData
    Public LastISPReturnData As ISPReturnData

    'configuration data
    Public NewConfigurationData As New ConfigurationData
    Public ShowBackgroundSave As Boolean

    'nic data
    Public NicValueDown As New System.Diagnostics.PerformanceCounter
    Public NicValueUp As New System.Diagnostics.PerformanceCounter
    Public NicUsageDown As Double
    Public NicUsageUp As Double
    Public LastNicUsageDown As Double
    Public LastNicUsageUp As Double
    Public ZeroUpdateCount As Integer

    'misc data
    Private HIcon As IntPtr
    Public AppStartingFlag As Boolean = True
    Public AppClosingFlag As Boolean = False
    Private RebuildfrmStats As Boolean = False

    'forms
    Private frmAbout As frmAbout
    Public NewfrmStats As frmStats

    'notify icon
    Friend WithEvents nfiUsage As New NotifyIcon

    'menu
    Public notifyiconMnu As ContextMenu

    'timers
    Public tmrISPUsage As Timer
    Public tmrNic As Timer

    Sub Main(ByVal args() As String)
        Try
            If args IsNot Nothing AndAlso args.Length > 0 AndAlso args(0) = "Install" Then
                'Set permissions on C:\ProgramData\UsageAgent folder
                Dim di As DirectoryInfo = New DirectoryInfo(GetAppDataPath())
                If Directory.Exists(di.FullName) = False Then
                    Directory.CreateDirectory(di.FullName)
                End If
                Dim ds As DirectorySecurity = di.GetAccessControl()
                ds.AddAccessRule(New FileSystemAccessRule("Everyone", FileSystemRights.ReadAndExecute Or FileSystemRights.Write Or FileSystemRights.Modify Or FileSystemRights.FullControl, InheritanceFlags.ObjectInherit Or InheritanceFlags.ContainerInherit, PropagationFlags.None, AccessControlType.Allow))
                di.SetAccessControl(ds)
                Exit Sub
            End If

            'already running, exit
            Dim myProcesses As Process() = Process.GetProcessesByName("UATrayIcon")
            If myProcesses.Length > 1 Then End
            myProcesses = Nothing

            'setup the default icon
            nfiUsage.Icon = icoUA
            If UnixDetected() = False Then nfiUsage.Text = "Usage Agent"
            nfiUsage.Visible = True

            'Insert all MenuItem objects into an array and add them to the context menu simultaneously
            Dim mnuItms(12) As MenuItem
            mnuItms(0) = New MenuItem("Current Usage", New EventHandler(AddressOf Usage))
            mnuItms(0).DefaultItem = True
            mnuItms(1) = New MenuItem("Reset Window Location", New EventHandler(AddressOf ResetLocation))
            mnuItms(2) = New MenuItem("Refresh ISP Usage", New EventHandler(AddressOf RefreshISPNow))
            mnuItms(2).Visible = False
            mnuItms(3) = New MenuItem("Reports", New EventHandler(AddressOf Reports))
            mnuItms(3).Visible = False
            mnuItms(4) = New MenuItem("Configure", New EventHandler(AddressOf ConfigureAccount))
            mnuItms(5) = New MenuItem("-")
            mnuItms(6) = New MenuItem("Open ISP Usage Home", New EventHandler(AddressOf OpenMyUsage))
            mnuItms(7) = New MenuItem("Open Usage Agent Home", New EventHandler(AddressOf OpenUsageAgent))
            mnuItms(8) = New MenuItem("-")
            mnuItms(9) = New MenuItem("Check for new version", New EventHandler(AddressOf CheckNewVersion))
            mnuItms(10) = New MenuItem("About", New EventHandler(AddressOf About))
            mnuItms(11) = New MenuItem("-")
            mnuItms(12) = New MenuItem("Shutdown Usage Agent", New EventHandler(AddressOf ExitSelect))
            notifyiconMnu = New ContextMenu(mnuItms)
            nfiUsage.ContextMenu = notifyiconMnu

            AddHandler nfiUsage.DoubleClick, AddressOf Usage

            notifyiconMnu.MenuItems(3).Visible = False

            'create timers
            tmrISPUsage = New Timer(New TimerCallback(AddressOf tmrISP_tick), Nothing, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite)
            tmrNic = New Timer(New TimerCallback(AddressOf tmrNic_tick), Nothing, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite)

            'load config
            If LoadConfiguration(NewConfigurationData) = True Then
                'if isp has not been validated, abort
                If NewConfigurationData.ISPValidated = False Then
                    MessageBox.Show("The connection to your ISP has not been validated. You must validate prior to running Usage Agent. Please re-run UA Configuration.", "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                    End
                End If

                'save showbackground
                ShowBackgroundSave = NewConfigurationData.ShowBackground
                'force to show
                NewConfigurationData.ShowBackground = True

                If NewConfigurationData.RetrieveNICData = True Then
                    Try
                        'enable tcp performance if currently disabled
                        RegEnablePerfCounter()

                        Try
                            NicValueDown.CategoryName = "Network Interface"
                            NicValueDown.CounterName = "Bytes Received/sec"
                            NicValueDown.MachineName = "."

                            NicValueUp.CategoryName = "Network Interface"
                            NicValueUp.CounterName = "Bytes Sent/sec"
                            NicValueUp.MachineName = "."

                            'set nic
                            NicValueDown.InstanceName = NewConfigurationData.NICName
                            NicValueUp.InstanceName = NewConfigurationData.NICName
                        Catch ex As Exception
                            NewConfigurationData.RetrieveNICData = False
                        End Try

                    Catch ex As Exception
                        NewConfigurationData.RetrieveNICData = False
                        MessageBox.Show("There was an error attempting to find your NIC's. Disabling NIC Monitoring.", "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                    End Try
                End If

                'start timers
                If NewConfigurationData.RetrieveNICData = True Then
                    tmrNic.Change(0, 1000)
                    'wait till done
                    System.Threading.Thread.Sleep(500)
                End If

                notifyiconMnu.MenuItems(3).Visible = NewConfigurationData.LogEnabled

                tmrISPUsage.Change(0, CInt(NewConfigurationData.UpdateInterval) * 60000)
                notifyiconMnu.MenuItems(2).Visible = True

                If NewConfigurationData.IconStatsShowStartup = True Then ShowStats()
                If NewConfigurationData.CheckVersionOnStartup = True Then CheckVersionSUB(True)
            Else
                MessageBox.Show("Error reading config file. Please re-enter your details.", "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                ShowConfig()
            End If
            Application.Run()

        Catch ex As Exception
            MessageBox.Show(ex.Message, "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
            End
        End Try
    End Sub

    Sub Usage(ByVal sender As Object, ByVal e As System.EventArgs)
        If notifyiconMnu.MenuItems(0).Enabled = True Then ShowStats()
    End Sub

    Sub ConfigureAccount(ByVal sender As Object, ByVal e As System.EventArgs)
        ShowConfig()
    End Sub

    Sub About(ByVal sender As Object, ByVal e As System.EventArgs)
        If frmAbout Is Nothing Then
            frmAbout = New frmAbout
            'add close event
            AddHandler frmAbout.Closed, AddressOf FormClosed
            frmAbout.Show()
        Else
            frmAbout.Visible = True
            frmAbout.Activate()
        End If
    End Sub

    Sub Reports(ByVal sender As Object, ByVal e As System.EventArgs)
        Try
            If UnixDetected() = False Then
                NewShell(Application.StartupPath, Application.StartupPath & Path.DirectorySeparatorChar & "uareports.exe", "", False)
            Else
                NewShell(Application.StartupPath, "mono", "uareports.exe", False)
            End If
        Catch ex As Exception
            MessageBox.Show(ex.ToString, "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try
    End Sub

    Sub ShowConfig()
        Try
            'disable timers
            tmrISPUsage.Change(Timeout.Infinite, Timeout.Infinite)
            tmrNic.Change(Timeout.Infinite, Timeout.Infinite)
            notifyiconMnu.MenuItems(2).Enabled = False

            'hide usage window if visible
            If NewfrmStats IsNot Nothing Then
                If NewfrmStats.Visible = True Then NewfrmStats.Close()
            End If

            If UnixDetected() = False Then
                NewShell(Application.StartupPath, Application.StartupPath & Path.DirectorySeparatorChar & "uaconfiguration.exe", "", False, True)
            Else
                NewShell(Application.StartupPath, "mono", "uaconfiguration.exe", False)
            End If

        Catch ex As Exception
            MessageBox.Show(ex.ToString, "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try
    End Sub

    Sub OpenMyUsage(ByVal sender As Object, ByVal e As System.EventArgs)
        Dim URL As String = GetISPHomePage(NewConfigurationData.ISPName)
        System.Diagnostics.Process.Start(URL)
    End Sub

    Sub OpenUsageAgent(ByVal sender As Object, ByVal e As System.EventArgs)
        System.Diagnostics.Process.Start("http://usageagent.sourceforge.net/")
    End Sub

    Sub CheckNewVersion(ByVal sender As Object, ByVal e As System.EventArgs)
        CheckVersionSUB(False)
    End Sub

    Sub CheckVersionSUB(ByVal bolNewOnly As Boolean)
        Dim Arguments As String = ""
        If bolNewOnly = True Then Arguments = "-silent"

        If UnixDetected() = False Then
            NewShell(Application.StartupPath, Application.StartupPath & Path.DirectorySeparatorChar & "uaupdate.exe", Arguments, False)
        Else
            NewShell(Application.StartupPath, "mono", "uaupdate.exe", False)
        End If
    End Sub

    Sub ShowStats()
        'exit of disabled
        If notifyiconMnu.MenuItems(2).Enabled = False Then Exit Sub

        'check if there is nothing to show
        If NewConfigurationData.ShowISPGraph = False And NewConfigurationData.ShowISPStats = False And NewConfigurationData.ShowNICStats = False And (NewConfigurationData.RetrieveNICData = False Or NewConfigurationData.IconShowNICGraph = False) Then
            'force show all
            NewConfigurationData.ShowISPGraph = True
            NewConfigurationData.ShowISPStats = True
            NewConfigurationData.ShowNICStats = True
            NewConfigurationData.IconShowNICGraph = True
        End If

        If NewfrmStats Is Nothing Then
            NewfrmStats = New frmStats
            'add close event
            AddHandler NewfrmStats.Closed, AddressOf FormClosed
            NewfrmStats.Show()
        Else
            If NewfrmStats.Visible = False Then
                NewfrmStats.Close()
                NewfrmStats = New frmStats
                'add close event
                AddHandler NewfrmStats.Closed, AddressOf FormClosed
                NewfrmStats.Show()
            Else
                NewfrmStats.Close()
            End If
        End If
    End Sub

    Sub ExitSelect(ByVal sender As Object, ByVal e As System.EventArgs)
        AppClosingFlag = True

        'restore showbackground
        NewConfigurationData.ShowBackground = ShowBackgroundSave

        'save config
        SaveConfiguration(NewConfigurationData)

        'stop timers
        tmrISPUsage.Change(0, System.Threading.Timeout.Infinite)

        'dispose of icon
        nfiUsage.Dispose()
        Application.Exit()
    End Sub

    Sub RefreshISPNow(ByVal sender As Object, ByVal e As System.EventArgs)
        RetrieveISPStats()
    End Sub

    Sub ResetLocation(ByVal sender As Object, ByVal e As System.EventArgs)
        NewConfigurationData.IconStartX = CInt((SystemInformation.WorkingArea.Width - frmStats.Width) / 2)
        NewConfigurationData.IconStartY = CInt((SystemInformation.WorkingArea.Height - frmStats.Height) / 2)

        If NewfrmStats IsNot Nothing Then
            'position form
            NewfrmStats.Location = New Point(NewConfigurationData.IconStartX, NewConfigurationData.IconStartY)
        End If
    End Sub

    Public Sub FormClosed(ByVal sender As Object, ByVal e As System.EventArgs)
        'dispose of object so we can track it's status
        If CType(sender, Form).Name = "frmAbout" Then frmAbout = Nothing
        If CType(sender, Form).Name = "frmStats" Then NewfrmStats = Nothing
    End Sub

    Sub tmrISP_tick(ByVal state As [Object])
        'allow error to show if required
        If NewfrmStats IsNot Nothing Then NewfrmStats.ShowError = True

        Try
            If NewConfigurationData.Username <> "" And NewConfigurationData.Password <> "" Then RetrieveISPStats()
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try
    End Sub

    Public Sub RetrieveISPStats()
        'fetching
        If ISPReturnData IsNot Nothing Then ISPReturnData.Status = 1

        'allow error to show if required
        If NewfrmStats IsNot Nothing Then NewfrmStats.ShowError = True

        Try
            'create update thread
            Dim MyThreadStart As New ThreadStart(AddressOf HandleThread)
            Dim MyWorkerThread As New Thread(MyThreadStart)
            MyWorkerThread.Name = "UsageAgent ISP Update"
            MyWorkerThread.Start()
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try
    End Sub

    Sub HandleThread()
        Try
            'exit if we are closing up
            If AppClosingFlag = True Then Exit Sub

            'if 1st run, delay if reqired
            If AppStartingFlag = True Then
                If CInt(NewConfigurationData.IconUpdateDelay) > 0 And CInt(NewConfigurationData.IconUpdateDelay) < 61 Then
                    'initial delay
                    System.Threading.Thread.Sleep(CInt(NewConfigurationData.IconUpdateDelay * 1000))
                End If
                AppStartingFlag = False
            End If

            'backup existing icon
            Dim icoSave As Icon = CType(nfiUsage.Icon.Clone, Icon)
            'Dim icoSave As Icon = nfiUsage.Icon

            'setup temp icon
            Dim NewBitmap As Bitmap = Bitmap.FromHicon(icoSave.Handle)
            Dim g As Graphics = Graphics.FromImage(NewBitmap)

            'draw highlight
            g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
            g.FillEllipse(Brushes.Yellow, New Rectangle(9, 0, 6, 6))
            g.DrawEllipse(Pens.Black, New Rectangle(9, 0, 6, 6))

            If UnixDetected() = False Then
                DestroyIcon(HIcon)
                HIcon = NewBitmap.GetHicon()
                nfiUsage.Icon = Icon.FromHandle(HIcon)
            Else
                If nfiUsage.Icon IsNot Nothing Then nfiUsage.Icon.Dispose()
                'nfiUsage.Icon = IconEncoder.Converter.BitmapToIcon(NewBitmap)
            End If

            'save old stats
            If ISPReturnData IsNot Nothing Then
                LastISPReturnData = New ISPReturnData
                LastISPReturnData = ISPReturnData
                If LastISPReturnData.Status = 1 Then LastISPReturnData.Status = 2
            End If

            'get usage
            ISPReturnData = New ISPData(NewConfigurationData).ISPReturnData

            'exit if we are closing up
            If AppClosingFlag = True Then Exit Sub

            'check for error
            If ISPReturnData.ErrorMessage = "" Then
                'check for log output
                If NewConfigurationData.LogEnabled = True Then WriteLog(ISPReturnData, NewConfigurationData.RetrieveNICData, NicUsageDown, NicUsageUp)

                'check for text log output
                If NewConfigurationData.ExportTextLog = True Then ExportTextLog(ISPReturnData, NewConfigurationData)
            End If

            'restore old icon
            nfiUsage.Icon = icoSave

            If LastISPReturnData IsNot Nothing Then
                'if last fetch was good, but current bad, then restore and ignore
                If LastISPReturnData.Status <> 3 And ISPReturnData.Status = 3 Then
                    ISPReturnData = LastISPReturnData
                    ISPReturnData.ShowWarning = True
                End If
            End If

            'make usage icon
            If ISPReturnData.Status = 3 Then
                nfiUsage.Text = "Unknown"
                If NewConfigurationData.RetrieveNICData = True Then nfiUsage.Text = Left(nfiUsage.Text & vbLf & "Down: " & Left(Format((NicUsageDown - LastNicUsageDown) / 1024, "0.00"), 4) & " | Up: " & Left(Format(((NicUsageUp - LastNicUsageUp) * 2) / 1024, "0.00"), 4), 63)
                nfiUsage.Icon = icoUA
                Exit Sub
            Else
                If UnixDetected() = False Then
                    If ISPReturnData.OffpeakNow = False Then
                        nfiUsage.Text = Left(ISPReturnData.PeakUsageRemainingDescription & " Remaining" & vbLf & ISPReturnData.PeakUsageRemainingPerDayDescription, 63)
                    Else
                        nfiUsage.Text = Left(ISPReturnData.OffpeakUsageRemainingDescription & " Remaining" & vbLf & ISPReturnData.OffpeakUsageRemainingPerDayDescription, 63)
                    End If
                    If NewConfigurationData.RetrieveNICData = True Then nfiUsage.Text = Left(nfiUsage.Text & vbLf & "Down: " & Left(Format((NicUsageDown - LastNicUsageDown) / 1024, "0.00"), 4) & " | Up: " & Left(Format(((NicUsageUp - LastNicUsageUp) * 2) / 1024, "0.00"), 4), 63)
                End If
            End If

            Dim myIconUsageValue As Integer
            If ISPReturnData.OffpeakNow = False Then
                myIconUsageValue = System.Convert.ToInt16(System.Math.Floor(ISPReturnData.PeakUsageValue))
            Else
                myIconUsageValue = System.Convert.ToInt16(System.Math.Floor(ISPReturnData.OffpeakUsageValue))
            End If

            'set background colour
            If NewConfigurationData.IconTrayISPColour = True Then
                Dim x As Integer
                Dim NewUsageColourValue As UsageColourValue
                Dim ColourSet As Boolean = False
                For x = NewConfigurationData.IconISPUsageColourValue.Items.Count - 1 To 0 Step -1
                    NewUsageColourValue = CType(NewConfigurationData.IconISPUsageColourValue.Items(x), UsageColourValue)
                    If myIconUsageValue >= NewUsageColourValue.Percentage Then
                        g.Clear(Color.FromArgb(CInt(NewUsageColourValue.Value)))
                        ColourSet = True
                        Exit For
                    End If
                Next
                If ColourSet = False Then g.Clear(Color.Transparent)
            Else
                If NewConfigurationData.IconTrayISPUsage = True Then
                    g.Clear(Color.Transparent)
                End If
            End If

            If NewConfigurationData.IconTrayISPUsage = False Then
                If NewConfigurationData.IconTrayISPColour = True Then
                    'merge default icon into bitmap
                    g.DrawImageUnscaled(icoUA.ToBitmap, 0, 0)
                    If UnixDetected() = False Then
                        DestroyIcon(HIcon)
                        HIcon = NewBitmap.GetHicon()
                        nfiUsage.Icon = Icon.FromHandle(HIcon)
                    Else
                        If nfiUsage.Icon IsNot Nothing Then nfiUsage.Icon.Dispose()
                        'nfiUsage.Icon = IconEncoder.Converter.BitmapToIcon(NewBitmap)
                    End If
                Else
                    'set default icon
                    nfiUsage.Icon = icoUA
                End If
            Else
                Dim FontSize As Single
                If myIconUsageValue.ToString.Length > 2 Then
                    FontSize = CSng(7 * (96 / GetDPI()))
                Else
                    FontSize = CSng(9 * (96 / GetDPI()))
                End If

                Dim NewFont As New Font("Arial", FontSize, FontStyle.Bold)
                Dim NewBrush As New SolidBrush(Color.Black)

                Dim x_offset As Integer = CInt(-g.MeasureString(myIconUsageValue.ToString, NewFont, 1000, StringFormat.GenericTypographic).Width / 2)

                g.TextRenderingHint = Drawing.Text.TextRenderingHint.ClearTypeGridFit

                If myIconUsageValue.ToString.Length > 2 Then
                    g.DrawString(myIconUsageValue.ToString, NewFont, NewBrush, x_offset + 9, 3, StringFormat.GenericTypographic)
                    g.DrawString(myIconUsageValue.ToString, NewFont, NewBrush, x_offset + 8, 3, StringFormat.GenericTypographic)
                    g.DrawString(myIconUsageValue.ToString, NewFont, NewBrush, x_offset + 7, 3, StringFormat.GenericTypographic)
                    g.DrawString(myIconUsageValue.ToString, NewFont, NewBrush, x_offset + 9, 1, StringFormat.GenericTypographic)
                    g.DrawString(myIconUsageValue.ToString, NewFont, NewBrush, x_offset + 8, 1, StringFormat.GenericTypographic)
                    g.DrawString(myIconUsageValue.ToString, NewFont, NewBrush, x_offset + 7, 1, StringFormat.GenericTypographic)
                    g.DrawString(myIconUsageValue.ToString, NewFont, NewBrush, x_offset + 9, 2, StringFormat.GenericTypographic)
                    g.DrawString(myIconUsageValue.ToString, NewFont, NewBrush, x_offset + 7, 2, StringFormat.GenericTypographic)
                    g.DrawString(myIconUsageValue.ToString, NewFont, Brushes.White, x_offset + 8, 2, StringFormat.GenericTypographic)
                Else
                    g.DrawString(myIconUsageValue.ToString, NewFont, NewBrush, x_offset + 9, 2, StringFormat.GenericTypographic)
                    g.DrawString(myIconUsageValue.ToString, NewFont, NewBrush, x_offset + 8, 2, StringFormat.GenericTypographic)
                    g.DrawString(myIconUsageValue.ToString, NewFont, NewBrush, x_offset + 7, 2, StringFormat.GenericTypographic)
                    g.DrawString(myIconUsageValue.ToString, NewFont, NewBrush, x_offset + 9, 0, StringFormat.GenericTypographic)
                    g.DrawString(myIconUsageValue.ToString, NewFont, NewBrush, x_offset + 8, 0, StringFormat.GenericTypographic)
                    g.DrawString(myIconUsageValue.ToString, NewFont, NewBrush, x_offset + 7, 0, StringFormat.GenericTypographic)
                    g.DrawString(myIconUsageValue.ToString, NewFont, NewBrush, x_offset + 9, 1, StringFormat.GenericTypographic)
                    g.DrawString(myIconUsageValue.ToString, NewFont, NewBrush, x_offset + 7, 1, StringFormat.GenericTypographic)
                    g.DrawString(myIconUsageValue.ToString, NewFont, Brushes.White, x_offset + 8, 1, StringFormat.GenericTypographic)
                End If

                If UnixDetected() = False Then
                    DestroyIcon(HIcon)
                    HIcon = NewBitmap.GetHicon()
                    nfiUsage.Icon = Icon.FromHandle(HIcon)
                Else
                    If nfiUsage.Icon IsNot Nothing Then nfiUsage.Icon.Dispose()
                    'nfiUsage.Icon = IconEncoder.Converter.BitmapToIcon(NewBitmap)
                End If

                'close up
                NewFont.Dispose()
                NewBrush.Dispose()
            End If

            g.Dispose()
            NewBitmap.Dispose()

            'restore showbackground
            NewConfigurationData.ShowBackground = ShowBackgroundSave

            'save config
            SaveConfiguration(NewConfigurationData)

            'force to show
            NewConfigurationData.ShowBackground = True

            If NewfrmStats IsNot Nothing Then
                If NewfrmStats.Visible = True Then
                    'force update
                    NewfrmStats.dteLastUpdated = Now
                End If
            End If

        Catch ex1 As System.ArgumentException
            'dont know why this happens, but i'll catch it anyway. May cause mem leak
            'this line causes the error:
            'TempBitmap = nfiUsage.Icon.ToBitmap
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        Finally
            'force garbage collection
            GC.WaitForPendingFinalizers()
            GC.Collect()
        End Try

    End Sub

    Sub tmrNic_tick(ByVal state As [Object])

        Try
            If NewConfigurationData.RetrieveNICData = False Then Exit Sub

            'exit if we are closing up
            If AppClosingFlag = True Then Exit Sub

            'get current nic values
            LastNicUsageDown = NicUsageDown
            LastNicUsageUp = NicUsageUp
            NicUsageDown = CDbl(NicValueDown.RawValue.ToString)
            NicUsageUp = CDbl(NicValueUp.RawValue.ToString)
            If LastNicUsageDown = 0 Then
                LastNicUsageDown = NicUsageDown
                LastNicUsageUp = NicUsageUp
            End If

            If NicUsageDown - LastNicUsageDown = 0 And NicUsageUp - LastNicUsageUp = 0 Then
                ZeroUpdateCount += 1
                If ZeroUpdateCount > 2 Then ZeroUpdateCount = 2
            Else
                ZeroUpdateCount = 0
            End If

            If ZeroUpdateCount < 2 Then
                If NewConfigurationData.IconTrayNICGraph = True Then
                    'setup temp icon
                    Dim TempBitmap As Bitmap = nfiUsage.Icon.ToBitmap
                    Dim TempBitmapGraphics As Graphics = Graphics.FromImage(TempBitmap)

                    Dim x As Double
                    Dim NewBrush As SolidBrush = Nothing

                    If ISPReturnData IsNot Nothing Then
                        If ISPReturnData.Status = 2 Then
                            Dim myIconUsageValue As Integer
                            Dim BackColour As Color
                            If ISPReturnData.OffpeakNow = False Then
                                myIconUsageValue = System.Convert.ToInt16(System.Math.Floor(ISPReturnData.PeakUsageValue))
                            Else
                                myIconUsageValue = System.Convert.ToInt16(System.Math.Floor(ISPReturnData.OffpeakUsageValue))
                            End If

                            If NewConfigurationData.IconTrayISPColour = True Then
                                Dim NewUsageColourValue As UsageColourValue
                                Dim ColourSet As Boolean = False
                                For x = NewConfigurationData.IconISPUsageColourValue.Items.Count - 1 To 0 Step -1
                                    NewUsageColourValue = CType(NewConfigurationData.IconISPUsageColourValue.Items(CInt(x)), UsageColourValue)
                                    If myIconUsageValue >= NewUsageColourValue.Percentage Then
                                        BackColour = Color.FromArgb(CInt(NewUsageColourValue.Value))
                                        ColourSet = True
                                        Exit For
                                    End If
                                Next
                                If ColourSet = False Then BackColour = Color.Transparent
                            Else
                                BackColour = Color.Transparent
                            End If

                            TempBitmapGraphics.SetClip(New Rectangle(0, 0, 16, 2))
                            TempBitmapGraphics.Clear(BackColour)
                            TempBitmapGraphics.ResetClip()
                            TempBitmapGraphics.SetClip(New Rectangle(0, 14, 16, 2))
                            TempBitmapGraphics.Clear(BackColour)
                            TempBitmapGraphics.ResetClip()
                        End If
                    End If

                    If NicUsageUp - LastNicUsageUp > 0 Then
                        'draw upload capacity
                        x = ((NicUsageUp - LastNicUsageUp) / (NewConfigurationData.IconNICCapacityUp * 1024)) * 16
                        If x < 1 Then x = 1
                        If x > 16 Then x = 16
                        NewBrush = New SolidBrush(Color.DarkRed)
                        TempBitmapGraphics.FillRectangle(NewBrush, 0, 0, CInt(x), 2)
                        NewBrush.Dispose()
                    End If

                    If NicUsageDown - LastNicUsageDown > 0 Then
                        'draw download capacity
                        x = ((NicUsageDown - LastNicUsageDown) / (NewConfigurationData.IconNICCapacityDown * 1024)) * 16
                        If x < 1 Then x = 1
                        If x > 16 Then x = 16
                        NewBrush = New SolidBrush(Color.DarkGreen)
                        TempBitmapGraphics.FillRectangle(NewBrush, 0, 14, CInt(x), 2)
                        NewBrush.Dispose()
                    End If

                    If UnixDetected() = False Then
                        DestroyIcon(HIcon)
                        HIcon = TempBitmap.GetHicon()
                        nfiUsage.Icon = Icon.FromHandle(HIcon)
                    Else
                        If nfiUsage.Icon IsNot Nothing Then nfiUsage.Icon.Dispose()
                        'nfiUsage.Icon = IconEncoder.Converter.BitmapToIcon(TempBitmap)
                    End If

                    TempBitmapGraphics.Dispose()
                    TempBitmap.Dispose()
                End If
                If ISPReturnData IsNot Nothing Then
                    'is isp data returned without error?
                    If ISPReturnData.Status = 2 Then
                        If ISPReturnData.OffpeakNow = False Then
                            nfiUsage.Text = ISPReturnData.PeakUsageRemainingDescription & " Remaining" & vbLf & ISPReturnData.PeakUsageRemainingPerDayDescription & vbLf
                        Else
                            nfiUsage.Text = ISPReturnData.OffpeakUsageRemainingDescription & " Remaining" & vbLf & ISPReturnData.OffpeakUsageRemainingPerDayDescription & vbLf
                        End If
                    Else
                        nfiUsage.Text = "Unknown" & vbLf
                    End If
                Else
                    nfiUsage.Text = ""
                End If
                nfiUsage.Text = Left(nfiUsage.Text & "Down: " & Left(Format((NicUsageDown - LastNicUsageDown) / 1024, "0.00"), 4) & " | Up: " & Left(Format((NicUsageUp - LastNicUsageUp) / 1024, "0.00"), 4), 63)
            End If

        Catch ex1 As System.ArgumentException
            'dont know why this happens, but i'll catch it anyway. May cause mem leak
            'this line causes the error:
            'TempBitmap = nfiUsage.Icon.ToBitmap
        Catch ex2 As System.InvalidOperationException
            NewConfigurationData.RetrieveNICData = False
            tmrNic.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite)
            MessageBox.Show("Usage Agent can no longer find your Network Card. This can occur if your NIC configuration has changed. All NIC reporting has been disabled. Please re-choose your NIC from the Configuration Form.", "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        Catch ex As Exception
            NewConfigurationData.RetrieveNICData = False
            tmrNic.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite)
            MessageBox.Show(ex.Message, "Usage Agent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try
    End Sub

End Module
